#include <stdlib.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>


#include "uart.h"



static unsigned char *Uart_inptr, *Srl_outptr;
unsigned char UART_buffer[BUFF_SIZE];
volatile unsigned char Srl_rx_int =0 ;// define the interrupt flag
volatile uint8_t Srl_rxbuff =0; // this byte is the last character read from the uart;


void Uart_init(void)
{
    Uart_inptr =  UART_buffer;
    Srl_outptr = UART_buffer;
    Srl_buff_cnt = 0;

	UART_CTRL_STATB =  (1<<TXEN) ;// eneble 8 bit communication and TX system // |_BV(RXB8) | _BV(RXEN)

	UART_BAUDRATE_REGH = 0x00;
	UART_BAUDRATE_REGL = 0x2F; // Send with 4800 baud  xtal = 3.68Mhz (CRYSTAL)

	//UART_CTRL_STATB |= (1<<2);//SET the uart tansmission size to 9 bit

	UART_CTRL_STATC |= ((1<<7)|(3<<1)); //Select the UCSRC and 8 bit communnication


	UART_CTRL_STATC &=0x7F; //Restore to UBRRH ;

	

	UART_CTRL_STATB |=(1<<RXEN) ; // RX system enabled
	UART_CTRL_STATB |=(1<<RXCIE) ; // RX system interrupt enabled

}


int Uart_putchar(uint8_t c)
{
    if (Srl_buff_cnt<BUFF_SIZE)
    {
		UART_CTRL_STATB &= ~_BV(UDRIE);				// Disable UART Data register empty interrupt
													// Making the routine ATOMIC
        *Uart_inptr = c;                             // Put character into buffer
        Uart_inptr++;                                // Increment pointer
        
        Srl_buff_cnt++;
        
        if (Uart_inptr >= UART_buffer + BUFF_SIZE)   // Pointer wrapping
            Uart_inptr = UART_buffer;
 
        UART_CTRL_STATB |= _BV(UDRIE);        		// Enable UART Data register empty interrupt
        
        return 1;
    } else {
        return 0;                               // Buffer is full
    }
        
}

/*
 * Send a C (NUL-terminated) string down the UART Tx.
 */
void Uart_printstr(const char *s)
{

  while (*s)
    {
      if (*s == '\n')
	Uart_putchar('\r');
      Uart_putchar(*s++);
    }
}

/*
 * Same as above, but the string is located in program memory,
 * so "lpm" instructions are needed to fetch it.
 */
void Uart_printstr_p(const char *s)
{
  char c;

  for (c = pgm_read_byte(s); c; ++s, c = pgm_read_byte(s))
    {
      if (c == '\n')
	Uart_putchar('\r');
      Uart_putchar(c);
    }
}


// Interrupt driven transmitter
SIGNAL(SIG_UART_DATA)
{
    UART_DATA_REG = *Srl_outptr;                    // Send next byte
    Srl_outptr++;                                   // Increment pointer
    
    if (Srl_outptr >= UART_buffer + BUFF_SIZE)      // Pointer wrapping
        Srl_outptr = UART_buffer;

    if(--Srl_buff_cnt == 0)                         // If buffer is empty:
		UART_CTRL_STATB &= ~_BV(UDRIE);	 		// disable interrupt			

}

SIGNAL(SIG_UART_RECV )
{
	static uint8_t data; // just a static for reading the data register (garbage or not)
	data = UART_DATA_REG; 

    if (bit_is_clear(UART_CTRL_STATB, FE))// test if there is no framing error
    {
		Srl_rxbuff = data;	// Store The Char in the global var 
		Srl_rx_int = 1; 	// Signal a Character in the Uart
	}
    else
    {
    	// Error condition is not (yet) handled here  
		// This is possible because the transmission works whit long blocks   
    }
}   


